Default scripts LoRaWAN
- Overview
- S0
- Modbus
- M-Bus
- W M-Bus
Here you can find default LoRaWAN LUA scripts for IoT Converter
-- Copyright 2021 ACRIOS Systems s.r.o.
-- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
-- 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
-- 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
-- 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
function wordToBuffer(word)
-- little endian
local buff = ""
buff = buff .. string.char(word%256) .. string.char((word/256)%256) .. string.char(((word/256)/256)%256) .. string.char((((word/256)/256)/256)%256)
return buff
end
-- get and format S0 inputs
function getS0Data()
s00 = api.S0readCounter(0)
print("S0-0: "..tostring(s00))
s01 = api.S0readCounter(1)
print("S0-1: "..tostring(s01))
s02 = api.S0readCounter(2)
print("S0-2: "..tostring(s02))
s03 = api.S0readCounter(3)
print("S0-3: "..tostring(s03))
-- read old values
s00_l = api.getVar(16)
s01_l = api.getVar(17)
s02_l = api.getVar(18)
s03_l = api.getVar(19)
s00_ll = api.getVar(20)
s01_ll = api.getVar(21)
s02_ll = api.getVar(22)
s03_ll = api.getVar(23)
-- update old values
api.setVar(16, s00)
api.setVar(17, s01)
api.setVar(18, s02)
api.setVar(19, s03)
api.setVar(20, s00_l)
api.setVar(21, s01_l)
api.setVar(22, s02_l)
api.setVar(23, s03_l)
-- get battery voltage
v = api.getBatteryVoltage()
-- assemble the frame
buf = string.char(5) -- device class
buf = buf .. string.char(v%256) .. string.char((v/256)%256)
buf = buf .. wordToBuffer(s00) .. wordToBuffer(s00_l) .. wordToBuffer(s00_ll)
buf = buf .. wordToBuffer(s01) .. wordToBuffer(s01_l) .. wordToBuffer(s01_ll)
buf = buf .. wordToBuffer(s02) .. wordToBuffer(s02_l) .. wordToBuffer(s02_ll)
buf = buf .. wordToBuffer(s03) .. wordToBuffer(s03_l) .. wordToBuffer(s03_ll)
-- print the frame
print("Frame in hex: <devClass, voltage, S0_0, S0_0_last, ...>")
api.dumpArray(buf)
return buf
end
function onWake ()
buf,err,ack,wake = api.getGUIContext()
print("onWake(), periodic wake up")
buf = getS0Data()
print("Sending to LORA")
api.loraSend(ack,20000,buf)
print("Done sending")
print("No error, sent to lora")
api.wakeUpIn(0,0,wake,0)
end
function onThreshold ()
buf,err,ack,wake,src = api.getGUIContext()
print("onThreshold(), reason S0: " .. tostring(src))
buf = getS0Data()
print("Sending to LORA")
api.loraSend(ack,20000,buf)
print("Done sending")
print("No error, sent to lora")
end
function onStartup()
print("onStartup(), S0 persistent emulation...")
--set to threshold
api.S0setThreshold(0, 0)
api.S0setThreshold(1, 0)
api.S0setThreshold(2, 0)
api.S0setThreshold(3, 0)
s00 = api.getVar(20)
s01 = api.getVar(21)
s02 = api.getVar(22)
s03 = api.getVar(23)
api.S0initializeCounter(0, s00)
api.S0initializeCounter(1, s01)
api.S0initializeCounter(2, s02)
api.S0initializeCounter(3, s03)
end
-- Copyright 2021 ACRIOS Systems s.r.o.
-- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
-- 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
-- 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
-- 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-----------------------
--- CONFIGURATION -----
-----------------------
----- LoRaWAN ----------
ack = 0 -- 1 for acknowledged, 0 for non-acknowledged
port = 100 -- transmit port
receiveTimeout = 10000 -- the maximum execution time in milliseconds
----- Modbus -----------
baudrate = 9600 -- baudrate: up to 921600 baud
parity = 0 -- communication parity: 0 for none, 1 for odd and 2 for even parity
stopBits = 1 -- number of stop bits: 1 or 2
dataBits = 8 -- number of data bits: 7 or 8
rxTimeout = 500 -- slave device receive timeout in ms
------ Timing ---------
-- device wakeup interval
periodHours = 2
periodMinutes = 30
-----------------------
-----------------------
-- CONFIGURATION END --
-----------------------
function onWake ()
-- set link parameters - e.g. 9600 baud, 8N1
api.rs485Setup(baudrate,parity,stopBits,dataBits)
api.rs485State(1)
-- EXAMPLE Modbus request:
-- check our applicaton notes or https://simplymodbus.ca/FC03.htm
-- req = ""
-- SLAVE ADDRESS (0xAA)| FUNCTION CODE (0x04)|
-- MSB REG ADDR (0x00) | LSB REG ADDR (0x08) |
-- MSB REG COUNT (0x00) | LSB REG COUNT (0x01)
-- req = pack.pack('<b6', 0xAA, 0x04, 0x00, 0x08, 0x00, 0x01)
-- crc = api.modbusCrc(req)
-- req = req .. crc -- add CRC, request is complete and ready for sending
if req == nil then
print("Please provide configuration!")
ans = "NO CONFIGURATION PROVIDED!"
else
print("To RS485: ")
api.dumpArray(req)
api.rs485Send(req)
ans,length=api.rs485Receive(rxTimeout)
print("From RS485: ")
api.dumpArray(ans)
api.delayms(500)
api.rs485State(0)
end
if #ans < 1 then
buf = "NO DATA RECEIVED"
else
buf = ans
end
print("To LoRaWAN: ")
api.dumpArray(buf)
print("Sending to LoRaWAN")
res, rxport, rcvd = api.loraSend(ack, receiveTimeout, buf, port)
print("Done sending")
print("Sleep now, wake in " .. tostring(periodHours) .. "hrs:" .. tostring(periodMinutes) .. "mins.....")
api.wakeUpIn(0,periodHours,periodMinutes,0)
end
function onStartup()
print("Starting up LoRaWAN default Modbus script")
end
-- Copyright 2021 ACRIOS Systems s.r.o.
-- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
-- 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
-- 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
-- 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-----------------------
--- CONFIGURATION -----
-----------------------
----- LoRaWAN ----------
ack = 0 -- 1 for acknowledged, 0 for non-acknowledged
port = 100 -- transmit port
receiveTimeout = 10000 -- the maximum execution time in milliseconds
----- M-BUS -----------
baudrate = 2400 -- baudrate: up to 921600 baud
parity = 2 -- communication parity: 0 for none, 1 for odd and 2 for even parity
stopBits = 1 -- number of stop bits: 1 or 2
dataBits = 8 -- number of data bits: 7 or 8
------ Timing ---------
-- device wakeup interval
periodHours = 2
periodMinutes = 30
-----------------------
-----------------------
-- CONFIGURATION END --
-----------------------
function onWake ()
-- set link parameters - 2400 baud, 8E1
api.mbusSetup(baudrate,parity,stopBits,dataBits)
api.mbusState(1)
api.delayms(2000)
-- CREATE MBUS QUERY --
-- UD2
--b=pack.pack('<b5', 0x10, 0x5B, 0xFE, 0x59, 0x16)
b=pack.pack('<b5', 0x10, 0x7B, 0xFE, (0x7B+0xFE)%256, 0x16)
status,c,a,ci,ans = api.mbusTransaction(b,3000,1)
api.mbusState(0)
print("From MBus Calorimeter: ")
api.dumpArray(ans)
if #ans < 1 then
buf = "NO DATA RECEIVED"
else
buf = ans
end
print("To LoRaWAN: ")
api.dumpArray(buf)
print("Sending to LoRaWAN")
res, rxport, rcvd = api.loraSend(ack, receiveTimeout, buf, port)
print("Done sending")
print("Sleep now, wake in " .. tostring(periodHours) .. "hrs:" .. tostring(periodMinutes) .. "mins.....")
api.wakeUpIn(0,periodHours,periodMinutes,0)
end
function onStartup()
print("Starting up LoRaWAN MBUS default script")
end
-- Copyright 2021 ACRIOS Systems s.r.o.
-- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
-- 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
-- 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
-- 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---- CONFIGURATION ----
periodDays = 1
periodHours = 0
periodMinutes = 0
ack = 1 -- 1 for acknowledged, 0 for non-acknowledged delivery
---------------------
function loraSendBig(raw, filterId)
ret, port, cfg = api.loraSend(ack, 5000, string.char(1)..string.sub(raw,1,50), filterId)
processConfig(ret, port, cfg)
if #raw > 50 then
ret, port, cfg = api.loraSend(ack, 5000, string.char(2)..string.sub(raw,51,100), filterId)
processConfig(ret, port, cfg)
if #raw > 100 then
ret, port, cfg = api.loraSend(ack, 5000, string.char(3)..string.sub(raw,101,150), filterId)
processConfig(ret, port, cfg)
if #raw > 150 then
ret, port, cfg = api.loraSend(ack, 5000, string.char(4)..string.sub(raw,151,200), filterId)
processConfig(ret, port, cfg)
if #raw > 200 then
ret, port, cfg = api.loraSend(ack, 5000, string.char(5)..string.sub(raw,201,250), filterId)
processConfig(ret, port, cfg)
end
end
end
end
end
function processConfig(ret, port, cfg)
-- port 230 is selected for new filter configuration
if port == 230 then
print("New filter config:")
if cfg == nil or #cfg < 3 then
print("Purge filter, receive all")
api.wmbusFilter("purge")
filterLength = 0
api.setVar(1, filterLength)
else
api.dumpArray(cfg)
api.wmbusFilter("populate", cfg)
filterLength = #cfg/4
filterIdHasReceived = {}
for i=1, filterLength do
filterIdHasReceived[i] = 0
end
maxTimeout = 32000*filterLength
if maxTimeout < 120000 then
maxTimeout = 120000
end
api.setVar(1, filterLength)
end
end
-- port 231 is used to switch between WMBUS modes
if port == 231 then
if cfg == nil or cfg == '' then
print("Bad WMBUS mode, Specify C1 or T1 or S1")
else
print("New WMBUS mode: "..cfg)
api.wmbusSetup(10, "master", cfg, 1)
end
end
end
function onWake ()
filterLength = api.getVar(1)
done = 0
print("Filter length: " .. tostring(filterLength))
if filterLength > 0 then
filterIdHasReceived = {}
for i=1, filterLength do
filterIdHasReceived[i] = 0
end
else
print("Error - no filter setup!")
ret, port, cfg = api.loraSend(ack,10000,'NO FILTER, send ID filter to 230, mode to 231', 240)
processConfig(ret, port, cfg)
end
start = api.getTick()
maxTimeout = 32000*filterLength
if maxTimeout < 120000 then
maxTimeout = 120000
end
-- receive WMBUS frames and upload to LoRaWAN in format [[0x chunkCount chunkNumber] raw wmbus frame]
-- to port corresponding to Filter ID
while filterLength > 0 do
while true do
-- if timeout, report not responding units
now = api.getTick()
if now - start > maxTimeout then
failing = ""
for i=1, filterLength do
failing = failing .. string.char(filterIdHasReceived[i])
end
print("List of failing Filter IDs:")
api.dumpArray(failing)
-- send list of failing devices to port 241
ret, port, cfg = api.loraSend(ack,10000, failing, 241)
processConfig(ret, port, cfg)
print("Timeout receiving data from all meters...")
-- wake up later
api.wakeUpIn(periodDays, periodHours, periodMinutes, 0)
return
end
status, CI, manID, id, ver, devType, ctrlInfo, data, raw, filterId = api.wmbusReceiveFrame(60000, 0)
if raw ~= nil then
print("Received valid wMBUS frame...")
break
end
end
if filterId ~= nil then
if filterId > 0 then
if filterIdHasReceived[filterId] == 0 then
done = done + 1
print("Upload data from node "..tostring(filterId).." to LoRaWAN. ("..tostring(done).."/"..tostring(filterLength)..")")
filterIdHasReceived[filterId] = 1
api.dumpArray(string.char(filterId) .. raw)
loraSendBig(raw, filterId)
else
print("Data from meter "..tostring(filterId).." already received.")
end
test = 1
for i=1, filterLength do
if filterIdHasReceived[i] == 0 then
test = 0
break
end
end
if test == 1 then
print("Received data from all meters, sleeping.......")
-- wake up later
api.wakeUpIn(periodDays, periodHours, periodMinutes, 0)
return
end
end
end
end
end
function onStartup()
print("Starting up WMBUS to LoRaWAN script, V1.3")
-- Initial filter ids: 0x01673213, 0x19854733 ... (in little endian)
-- COMMENT OUT START
--filter = ""
--filter = filter .. string.char(0x13, 0x32, 0x67, 0x01) -- 0x01673213
--filter = filter .. string.char(0x33, 0x47, 0x85, 0x19) -- 0x19854733
--api.wmbusFilter("populate", filter)
-- COMMENT OUT END
ret, filterLength = api.wmbusFilter("fetch")
api.setVar(1, filterLength)
-- Start receiving at C1/T1 mode/frequency
api.wmbusSetup(10, "master","T1", 1)
end